package gov.nasa.anml.lifted;

import java.util.*;

import gov.nasa.anml.PDDL;
import gov.nasa.anml.State;
import gov.nasa.anml.utility.SimpleObject;
import gov.nasa.anml.utility.SimpleString;
import static gov.nasa.anml.lifted.IdentifierCode.*;

// do need decl and refs for functions because of args.
// but don't need to use long-winded "declaration" suffix
public class FluentFunction<T extends SimpleObject<? super T>> extends Term<T,T> {
	public Type<T> type;

	public ArrayList<HashSet<SimpleObject<?>>> reachable;

	public FluentFunction() {}
	public FluentFunction(String n) {name=new SimpleString(n);}
	public FluentFunction(SimpleString n) {name=n;}
	public FluentFunction(SimpleString n,Type<T> t) {name=n;type=t;}

	public void initGrounding() {
		reachable = new ArrayList<HashSet<SimpleObject<?>>>();
		for (int i = parameters.count - 1; i >= 0; --i) {
			reachable.add(new HashSet<SimpleObject<?>>());
		}
	}

	public TypeCode typeCode() {
		return type.typeCode();
	}

	public IdentifierCode idCode() {
		return FluentFunction;
	}
	
	transient PDDL.Predicate boolPDDL;
	transient PDDL.Function floatPDDL;
	
	public void translateDecl(PDDL pddl,Interval unit) {
		if (typeCode() == TypeCode.Boolean) {
			if (boolPDDL != null)
				return;
			int length = pddl.bufAppend(name);
			boolPDDL = pddl.new Predicate(pddl.bufToString());
			pddl.bufReset(length);
			pddl.predicates.add(boolPDDL);
			boolPDDL.context.addAll(pddl.context);
			for (Parameter<?> p : parameters.table) {
				p.translateDecl(pddl,boolPDDL);
			}
		} else if (typeCode() == TypeCode.Float) {
			if (floatPDDL != null)
				return;
			int length = pddl.bufAppend(name);
			floatPDDL = pddl.new Function(pddl.bufToString());
			pddl.bufReset(length);
			pddl.functions.add(floatPDDL);
			floatPDDL.context.addAll(pddl.context);
			for (Parameter<?> p : parameters.table) {
				p.translateDecl(pddl,floatPDDL);
			}
		}
	}
	
	public History<T> storage(State p, State c) {
		// the more general thing is to find the function id, instead of the first 0, 
		// and then to find the correct binding of the parameters to arguments instead of the second 0.
		return (History<T>) p.functions.get(0).get(this.reachable.get(0));
	}
	public T value(State s) {
		return (T) s.functions.get(0).get(this.reachable.get(0)).value;
	}

	

}
